//
//  JVNetworkFlowMonitor.m
//  iosframework
//
//  Created by 马泽岩 on 2017/11/6.
//  Copyright © 2017年 ljs. All rights reserved.
//

#import "JVNetworkFlowMonitor.h"
#include <ifaddrs.h>
#include <sys/socket.h>
#include <net/if.h>


@interface JVNetworkFlowMonitor ()

@property (nonatomic, assign) int clearAfterLaunch;

@property (nonatomic, assign) int allHistoryFlow;
@property (nonatomic, assign) int currentFlow;
@property (nonatomic, assign) int uploadFlow;
@property (nonatomic, assign) int uploadIncrements;
@property (nonatomic, assign) int downloadIncrements;
@property (nonatomic, assign) int downloadFlow;

@property (nonatomic, strong) dispatch_source_t timer;
@property (nonnull, copy) JVNetworkFlowMonitorBlock block;

@end

@implementation JVNetworkFlowMonitor


+ (JVNetworkFlowMonitor *)sharedInstance {
    static JVNetworkFlowMonitor * sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[JVNetworkFlowMonitor alloc] init];
        [sharedInstance resetData];
    });
    return sharedInstance;
}

- (void)resetData {
    self.allHistoryFlow = [self checkNetworkflow];
}

- (void)appDidEnterForeground {
    self.clearAfterLaunch = [self checkNetworkflow];
}

- (int)appDidEnterBackground {
    uint32_t current = [self checkNetworkflow];
    uint32_t expend = current- self.clearAfterLaunch;
    return expend;
}

-(void)checkNetworkflow:(JVNetworkFlowMonitorBlock)block{
    self.block = block;
    [self startTimer];
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.allHistoryFlow = 0;
        
    }
    return self;
}

-(void)startTimer {
    NSTimeInterval period = 1.0; //设置时间间隔
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒执行
    dispatch_source_set_event_handler(_timer, ^{
        [self checkNetworkflow];
        if (self.block) {
            self.block(self.currentFlow, self.uploadIncrements, self.downloadIncrements);
        }
    });
    
    [self resumeTimer];
}


-(void)pauseTimer {
    if(_timer){
        dispatch_suspend(_timer);
    }
}
-(void)resumeTimer {
    if(_timer){
        dispatch_resume(_timer);
    }
}
-(void)stopTimer {
    if(_timer){
        dispatch_source_cancel(_timer);
        _timer = nil;
    }
}


- (NSString *)bytesToAvaiUnit:(int)bytes {
    if(bytes < 1024) {
        return [NSString stringWithFormat:@"%dB", bytes];
    }else if(bytes >= 1024 && bytes < 1024 * 1024) {
        return [NSString stringWithFormat:@"%.1fKB", (double)bytes / 1024];
    }else if(bytes >= 1024 * 1024 && bytes < 1024 * 1024 * 1024) {
        return [NSString stringWithFormat:@"%.2fMB", (double)bytes / (1024 * 1024)];
    }else {
        return [NSString stringWithFormat:@"%.3fGB", (double)bytes / (1024 * 1024 * 1024)];
    }
}

- (uint32_t)checkNetworkflow {
    struct ifaddrs *ifa_list = 0, *ifa;
    if (getifaddrs(&ifa_list) == -1) {
        return 0;
    }
    uint32_t iBytes     = 0;
    uint32_t oBytes     = 0;
    uint32_t allFlow    = 0;
    uint32_t wifiIBytes = 0;
    uint32_t wifiOBytes = 0;
    uint32_t wifiFlow   = 0;
    uint32_t wwanIBytes = 0;
    uint32_t wwanOBytes = 0;
    uint32_t wwanFlow   = 0;
    struct IF_DATA_TIMEVAL time ;
    for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
        if (AF_LINK != ifa->ifa_addr->sa_family) continue;
        if (!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING)) continue;
        if (ifa->ifa_data == 0) continue;
        // Not a loopback device.
        // network flow
        if (strncmp(ifa->ifa_name, "lo", 2)) {
            struct if_data *if_data = (struct if_data *)ifa->ifa_data;
            iBytes += if_data->ifi_ibytes;
            oBytes += if_data->ifi_obytes;
            allFlow = iBytes + oBytes;
            time = if_data->ifi_lastchange;
        }
        
        if (!strcmp(ifa->ifa_name, "en0")) {
            struct if_data *if_data = (struct if_data *)ifa->ifa_data;
            wifiIBytes += if_data->ifi_ibytes;
            wifiOBytes += if_data->ifi_obytes;
            wifiFlow    = wifiIBytes + wifiOBytes;
        }
        
        if (!strcmp(ifa->ifa_name, "pdp_ip0")) {
            struct if_data *if_data = (struct if_data *)ifa->ifa_data;
            wwanIBytes += if_data->ifi_ibytes;
            wwanOBytes += if_data->ifi_obytes;
            wwanFlow    = wwanIBytes + wwanOBytes;
        }
    }
    freeifaddrs(ifa_list);

    self.uploadIncrements = oBytes - self.uploadFlow;
    self.uploadFlow = oBytes;
    self.downloadIncrements = iBytes - self.downloadFlow;
    self.downloadFlow = iBytes;
    self.currentFlow = allFlow - self.allHistoryFlow;
    return allFlow;
}

@end
